﻿using Common.Core.DependencyInjection;
using Common.Core.Exceptions;
using Common.Core.Extension;
using Common.Core.Extensions;
using Common.Core.Requests;
using Microsoft.EntityFrameworkCore;
using NetByDocker.Core.Common;
using NetByDocker.Core.Npoi;
using NetByDocker.Domain.Entities;
using NetByDocker.Domain.Model.Enum;
using NetByDocker.Domain.Model.UserManage;
using NetByDocker.Model.UserManage;
using StackExchange.Profiling;

namespace NetByDocker.Service.UserManage;

public class UserService : IScopedDependency, IUserService
{
    private readonly IMapper _mapper;
    private readonly IBaseRepository<User> _userRep;
    private readonly IBaseRepository<Group> _groupRep;
    private readonly IUnitOfWork _unitOfWork;

    public UserService(IMapper mapper, IBaseRepository<User> userRep, IBaseRepository<Group> groupRep, IUnitOfWork unitOfWork)
    {
        _mapper = mapper;
        _userRep = userRep;
        _groupRep = groupRep;
        _unitOfWork = unitOfWork;
    }

    public async Task<GetQueryPageResult<GetUserPageInfoResponse>> GetPageListAsync(
        GetUserPageRequest request,
        CancellationToken cancellationToken)
    {
        var existUser = await _userRep.EntitiesNoTacking
                                      .AnyAsync(t => true, cancellationToken: cancellationToken)
                                      .ConfigureAwait(false);
        if (!existUser)
        {
            using (MiniProfiler.Current.Step("初始化用户数据"))
            {
                var grade1 = new Group("一班");
                await _groupRep.AddAsync(grade1).ConfigureAwait(false);
                var user1 = new User("admin1", "123456", "张三", SexEnum.Man, 10.12d,
                    grade1.Id);
                await _userRep.AddAsync(user1).ConfigureAwait(false);
                var user2 = new User("admin2", "123456", "李四", SexEnum.WoMan, 80.10d,
                    grade1.Id);
                await _userRep.AddAsync(user2).ConfigureAwait(false);
                await _unitOfWork.SaveChangesAsync(cancellationToken);
            }
        }

        using (MiniProfiler.Current.Step("查询用户信息"))
        {
            //先查询用户表
            var query = _userRep.EntitiesNoTacking
                                .QueryableWhereIf(!string.IsNullOrWhiteSpace(request.Keyword),
                                    t => t.Name == request.Keyword || t.Account == request.Keyword)
                                .OrderBy(t => t.CreateTime)
                                .Select(u =>
                                    new GetUserPageInfoResponse
                                    {
                                        Account = u.Account,
                                        Id = u.Id,
                                        Sex = u.Sex,
                                        Name = u.Name,
                                        Credit = u.Credit,
                                        ClassId = u.GroupId
                                    });

            //总条数
            var total = await query.CountAsync(cancellationToken: cancellationToken).ConfigureAwait(false);

            //用户集合
            var result = await query
                               .PagedBy(new GetPageSortRequest(request.PageIndex, request.PageSize))
                               .ToListAsync(cancellationToken: cancellationToken)
                               .ConfigureAwait(false);

            //查询上面查询出来的所有用户的班级ID
            var classIds = result.Select(t => t.ClassId).ToList();

            //根据班级id查询班级集合
            var classEntityList = await _groupRep.EntitiesNoTacking
                                                 .Where(t => classIds.Contains(t.Id))
                                                 .Select(t => new { ClassId = t.Id, t.Name })
                                                 .ToListAsync(cancellationToken: cancellationToken)
                                                 .ConfigureAwait(false);

            //循环用户集合，将班级的名字赋值给班级名字字段返回
            result.ForEach(t =>
            {
                var classEntity = classEntityList.Find(c => c.ClassId == t.ClassId);
                t.Name = classEntity?.Name;
            });

            return new GetQueryPageResult<GetUserPageInfoResponse>(result,
                new GetQueryPageResult(request.PageIndex, request.PageSize, total));
        }
    }

    public async Task<FileViewModel> ExportPageListAsync(
        GetUserPageRequest request, CancellationToken cancellationToken)
    {
        var userList = await _userRep.EntitiesNoTacking
                                     .QueryableWhereIf(!string.IsNullOrWhiteSpace(request.Keyword),
                                         t => t.Name == request.Keyword || t.Account == request.Keyword)
                                     .OrderBy(t => t.CreateTime)
                                     .Join(_groupRep.EntitiesNoTacking, u => u.GroupId, g => g.Id, (u, g) =>
                                         new GetUserPageInfoResponse
                                         {
                                             Account = u.Account,
                                             Id = u.Id,
                                             Sex = u.Sex,
                                             Name = u.Name,
                                             Credit = u.Credit,
                                             ClassName = g.Name,
                                             ClassId = g.Id
                                         })
                                     .PagedBy(new GetQueryPageResult { PageIndex = request.PageIndex, PageSize = request.PageSize, })
                                     .ToListAsync(cancellationToken: cancellationToken);
        var bytes = NpoiHelper.ExportExcel(userList);
        return new FileViewModel(bytes, "用户信息.xlsx");
    }

    public async Task<GetUserInfoResponse> GetDetailsAsync(long userId, CancellationToken cancellationToken)
    {
        var result = await _userRep.EntitiesNoTacking
                                   .Select(t =>
                                       new GetUserInfoResponse
                                       {
                                           Id = t.Id, Account = t.Account, Name = t.Name, Sex = t.Sex,
                                       })
                                   .FirstOrDefaultAsync(t => t.Id == userId, cancellationToken)
                                   .ConfigureAwait(false);
        return result;
    }

    public async Task<long> AddAsync(AddUserVm dto, CancellationToken cancellationToken)
    {
        var exist = await _userRep.EntitiesNoTacking
                                  .AnyAsync(t => !t.Deleted && t.Account == dto.Account, cancellationToken: cancellationToken)
                                  .ConfigureAwait(false);
        if (exist)
            throw new ParameterException("账号重复");

        //方案一：直接使用automapper映射
        //var user = _mapper.Map<User>(dto);

        //方案二：自己手动实例化对象
        var user = new User(dto.Account, dto.PassWord, dto.Name, dto.Sex, dto.Credit,
            dto.ClassId);

        await _userRep.AddAsync(user, true).ConfigureAwait(false);
        return user.Id;
    }

    public async Task<int> PatchUpdateAsync(long userId, UpdateUserVm dto, CancellationToken cancellationToken)
    {
        if (userId == 0)
            throw new ParameterException("用户标识无效");

        var user = await _userRep.Entities
                                 .FirstOrDefaultAsync(t => t.Id == userId, cancellationToken: cancellationToken)
                                 .ConfigureAwait(false);
        if (user is null)
            throw new ParameterException("用户标识无效");

        _mapper.Map(dto, user);
        return await _userRep.UpdateAsync(user, true).ConfigureAwait(false);
    }

    public async Task<int> UpdateAsync(long userId, UpdateUserVm dto, CancellationToken cancellationToken)
    {
        var entity = await _userRep.EntitiesNoTacking
                                   .FirstOrDefaultAsync(t => t.Id == userId, cancellationToken: cancellationToken)
                                   .ConfigureAwait(false);
        ParameterException.ThrowIfNull(entity, "对象不存在");

        if (!string.IsNullOrWhiteSpace(dto.Account))
            entity.Account = dto.Account;

        if (!string.IsNullOrWhiteSpace(dto.PassWord))
            entity.PassWord = dto.PassWord;

        return await _userRep.UpdateAsync(entity, true).ConfigureAwait(false);
    }

    public async Task<int> DeleteAsync(long userId, CancellationToken cancellationToken)
    {
        var entity = await _userRep.Entities
                                   .FirstOrDefaultAsync(t => t.Id == userId, cancellationToken: cancellationToken)
                                   .ConfigureAwait(false);
        if (entity is null)
            return 0;

        entity.SetDeleted("system", DateTime.Now.ToUnspecifiedDateTime());

        //逻辑删除
        return await _userRep.UpdateAsync(entity).ConfigureAwait(false);
    }
}